﻿using System;
using UnityEngine;

namespace Intersection111
{


    public struct AABB
    {
        public float XMin;
        public float YMin;
        public float XMax;
        public float YMax;
    }

    public struct Rectangle1
    {
        public Vector2 LeftBottom { private set; get; }
        public Vector2 RightBottom { private set; get; }
        public Vector2 LeftTop { private set; get; }
        public Vector2 RightTop { private set; get; }
        public Vector2 Center { private set; get; }
        public Vector2 XAxis { private set; get; }
        public Vector2 YAxis { private set; get; }
        public float Width { private set; get; }
        public float Height { private set; get; }
        public float HalfWidth { private set; get; }
        public float HalfHeight { private set; get; }

        /// <summary>
        /// 以底部中点展开矩形
        /// </summary>
        /// <param name="dir"></param>
        /// <param name="bottomCenter"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        public Rectangle1(Vector2 dir, Vector2 bottomCenter, float width, float height)
        {
            Vector2 dirN = dir.normalized;
            Vector2 rightDir = new Vector2(dirN.y, -dirN.x);
            Vector2 leftDir = new Vector2(-dirN.y, dirN.x);
            Vector2 topCenter = bottomCenter + height * dirN;
            Width = width;
            Height = height;
            HalfWidth = 0.5f * Width;
            HalfHeight = 0.5f * Height;
            LeftBottom = bottomCenter + leftDir * HalfWidth;
            RightBottom = bottomCenter + rightDir * HalfWidth;
            LeftTop = topCenter + leftDir * HalfWidth;
            RightTop = topCenter + rightDir * HalfWidth;
            XAxis = rightDir;
            YAxis = dirN;
            Center = (LeftBottom + RightTop) * 0.5f;
        }

        /// <summary>
        /// 以中心点展开矩形
        /// </summary>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <param name="center"></param>
        /// <param name="dir"></param>
        public Rectangle1(float width, float height, Vector2 center, Vector2 dir)
        {
            Width = width;
            Height = height;
            HalfWidth = 0.5f * Width;
            HalfHeight = 0.5f * Height;
            Vector2 dirN = dir.normalized;
            Vector2 rightDir = new Vector2(dirN.y, -dirN.x);
            Vector2 leftDir = new Vector2(-dirN.y, dirN.x);
            Vector2 topCenter = center + HalfHeight * dirN;
            Vector2 bottomCenter = center - HalfHeight * dirN;
            Vector2 leftOffset = leftDir * HalfWidth;
            Vector2 rightOffset = -leftOffset;
            LeftBottom = bottomCenter + leftOffset;
            RightBottom = bottomCenter + rightOffset;
            LeftTop = topCenter + leftOffset;
            RightTop = topCenter + rightOffset;
            XAxis = rightDir;
            YAxis = dirN;
            Center = center;
        }

        public AABB GetAABB()
        {
            AABB aabb = new AABB();
            aabb.XMin = BattleUtils.Min(LeftBottom.x, RightBottom.x, LeftTop.x, RightTop.x);
            aabb.XMax = BattleUtils.Max(LeftBottom.x, RightBottom.x, LeftTop.x, RightTop.x);
            aabb.YMin = BattleUtils.Min(LeftBottom.y, RightBottom.y, LeftTop.y, RightTop.y);
            aabb.YMax = BattleUtils.Max(LeftBottom.y, RightBottom.y, LeftTop.y, RightTop.y);
            return aabb;
        }

    }

    public class BattleUtils
    {
        // Start is called before the first frame update
        void Test()
        {
            var rect1 = new Rectangle1(1, 1, new Vector2(1, 1), Vector2.up);
            var rect2 = new Rectangle1(2, 2, new Vector2(5, 5), Vector2.right);

            var time1 = DateTime.Now;

            int cnt = 0;

            for (int i = 0; i < 100000; i++)
            {
                bool result = CheckRectInRect(rect1, rect2);
                //var result = IsIntersectRectWithRect(rect1.Corners, rect2.Corners);
                if (result == false)
                {
                    cnt++;
                }
            }

            var time2 = DateTime.Now;

            Debug.LogError(cnt);
            Debug.LogError($"矩形检测10W次：{(time2 - time1).TotalMilliseconds}");
        }

        public static bool CheckRectInRect(Rectangle1 rect1, Rectangle1 rect2)
        {
            //if (!CheckAABB(rect1.GetAABB(), rect2.GetAABB()))
            //{
            //    return false;
            //}
            bool isSeparation;
            isSeparation = CheckSeparation(rect1, rect2, true);
            if (isSeparation)
            {
                return false;
            }
            isSeparation = CheckSeparation(rect1, rect2, false);
            if (isSeparation)
            {
                return false;
            }
            isSeparation = CheckSeparation(rect2, rect1, true);
            if (isSeparation)
            {
                return false;
            }
            isSeparation = CheckSeparation(rect2, rect1, false);
            if (isSeparation)
            {
                return false;
            }
            return true;
        }

        private static bool CheckSeparation(Rectangle1 rect1, Rectangle1 rect2, bool isXAxis)
        {
            Vector2 axis = isXAxis ? rect2.XAxis : rect2.YAxis;
            float d11 = Vector2.Dot(rect1.RightBottom, axis);
            float d12 = Vector2.Dot(rect1.LeftBottom, axis);
            float d13 = Vector2.Dot(rect1.RightTop, axis);
            float d14 = Vector2.Dot(rect1.LeftTop, axis);
            float d1Max = Max(d11, d12, d13, d14);
            float d1Min = Min(d11, d12, d13, d14);
            float d21 = Vector2.Dot(rect2.RightBottom, axis);
            float d22 = Vector2.Dot(rect2.LeftBottom, axis);
            float d23 = Vector2.Dot(rect2.RightTop, axis);
            float d24 = Vector2.Dot(rect2.LeftTop, axis);
            float d2Max = Max(d21, d22, d23, d24);
            float d2Min = Min(d21, d22, d23, d24);
            return d2Min > d1Max || d2Max < d1Min;
        }
        public static float Max(float num1, float num2, float num3, float num4)
        {
            float max12 = Mathf.Max(num1, num2);
            float max23 = Mathf.Max(num3, num4);
            float max = Mathf.Max(max12, max23);
            return max;
        }

        public static float Min(float num1, float num2, float num3, float num4)
        {
            float min12 = Mathf.Min(num1, num2);
            float min23 = Mathf.Min(num3, num4);
            float min = Mathf.Min(min12, min23);
            return min;
        }

    }
}